

// http://zhufengpeixun.com/strong/html/103.3.webpack-ast.html#t75.2%20babel%20%E6%8F%92%E4%BB%B6

// 实现 babel 插件的时候有一些原则 1.尽可能复用老节点 2.尽可能少操作


// http://zhufengpeixun.com/strong/html/123.jsx-runtime.html
const types = require('@babel/types');
const pluginSyntaxJsx = require('@babel/plugin-syntax-jsx').default; //允许解析JSX
const pluginTransformReactJsx = {
    inherits:pluginSyntaxJsx, //继承
    visitor: {
        JSXElement(path) {
            // debugger
            let callExpression = buildJSXElementCall(path);
            path.replaceWith(callExpression); //用新的节点替换掉当前路径上老的节点
        }
    }
  
}
function buildJSXElementCall(path) {
    const openingPath = path.get("openingElement"); //获取openingElement的路径
    const {name} = openingPath.node.name; //h1
    const tag = types.stringLiteral(name); //{ type:"stringLiteral" ,value:'h1'}
    let attributes = [];
    const args = [tag];
    for (const attrPath of openingPath.get("attributes")) { //把两个老的属性节点放入attributes数组中
        attributes.push(attrPath.node);
    }
    const children = buildChildren(path.node);

    const props = attributes.map(convertAttribute);
    if (children.length > 0) {
       props.push(buildChildrenProperty(children));
    }
    const attributesObject = types.objectExpression(props); //创建参数对象
    args.push(attributesObject); 
    return call(path,"jsx", args);
}
/**
 * 将老的属性类型JSXAttribute对象映射成ObjectProperty
 * @param {*} node 
 * @returns 
 */
function convertAttribute(node) {
  const value = node.value;
  node.name.type = "Identifier";
  return types.objectProperty(node.name, value);
}
function buildChildren(node) {
  const elements = [];
  for (let i = 0; i < node.children.length; i++) {
    let child = node.children[i];
    if (types.isJSXText(child)) {
      elements.push(types.stringLiteral(child.value));
    }
  }
  return elements;
}


function buildChildrenProperty(children) {
  let childrenNode;
  if (children.length === 1) {
    childrenNode = children[0];
  } else if (children.length > 1) {
    childrenNode = types.arrayExpression(children);
  } else {
    return undefined;
  }
  return types.objectProperty(types.identifier("children"), childrenNode);
}

/**
 * 创建callExpression节点
 * @param {*} path 
 * @param {*} name 
 * @param {*} args 
 * @returns 
 */
function call(path,name, args) {
    const importedSource = 'react/jsx-runtime';
    const callee = addImport(path,name,importedSource);

    const node = types.callExpression(callee, args); 
    return node;
}
/**
 * 
 * @param {*} path 
 * @param {*} importName 导入的名称
 * @param {*} importedSource 导入的模块名
 */
function addImport(path,importName,importedSource){
    const programPath = path.find(p => p.isProgram()); //从当前的路径向上查找，找到Program路径
    const scope = programPath.scope; //获取作用域
    const localName = scope.generateUidIdentifier(importName); //jsx==>_jsx
    const specifiers  = [types.importSpecifier(localName, types.identifier(importName))];
    let statement = types.importDeclaration(specifiers, types.stringLiteral(importedSource));
    programPath.unshiftContainer("body", [statement]); //插到头部
    return localName;
}
module.exports = pluginTransformReactJsx;